import * as segmentStrategies from './segment-strategies.js'

export default class ArgsParser {
    /***
     * @type ArgsSchema
     */
    #schema

    /***
     *
     * @param schema : ArgsSchema
     */
    constructor(schema) {
        this.#schema = schema
    }

    parse(argsString, extractSegments = segmentStrategies.simple) {
        const args = {}
        const append = arg => this.#schema.typeOf(arg.flag).appendTo(args, arg)
        const segments = extractSegments(argsString)
        let flagCursor = 0
        const nextFlag = valueSpecified => valueSpecified ? flagCursor += 2 : flagCursor++

        while (flagCursor < segments.length) {
            const flag = this.#parseFlag(segments[flagCursor])
            const { value, valueSpecified } = this.#parseValue(flag, segments[flagCursor + 1])
            append({ flag, value })
            nextFlag(valueSpecified)
        }

        return { ...this.#schema.defaults, ...args }
    }

    #validateFlag(segment) {
        return segment?.match(/^-.$/) && this.#schema.defined(segment[1])
    }

    #parseFlag(segment) {
        if (!this.#validateFlag(segment)) throw `Invalid flag: ${segment}`
        return segment[1]
    }

    #parseValue(flag, segment) {
        const defaultValue = this.#schema.defaultOf(flag)
        const valueSpecified = !this.#validateFlag(segment)
        const type = this.#schema.typeOf(flag)
        return { value: type.parse(valueSpecified ? segment : undefined, defaultValue), valueSpecified }
    }
}
